package com.ruoyi.net.utils;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.net.domain.ElementAlarm;
import com.ruoyi.net.domain.NetElement;
import com.ruoyi.net.domain.Performance;
import com.ruoyi.net.service.IElementAlarmService;
import com.ruoyi.net.service.INetElementService;
import com.ruoyi.net.service.IPerformanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 接收设备返回的告警和性能数据
 */
//@Component
public class UdpReceiver {
    private static final Logger logger = LoggerFactory.getLogger(UdpReceiver.class);
    private static final int PORT = 17889; // 监听端口

    // 告警
    @Autowired
    private IElementAlarmService alarmService;

    // 性能
    @Autowired
    private IPerformanceService performanceService;

    @Autowired
    private INetElementService elementService;

    public UdpReceiver() {
        new Thread(() -> {
            DatagramSocket socket = null;
            try {
                socket = new DatagramSocket(PORT);
                byte[] receiveBuffer = new byte[1024];
                while (true) {
                    DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                    socket.receive(receivePacket);
                    String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
                    logger.info("Received UDP message: {}", message);
                    dealMsg(receivePacket);
                    Thread.sleep(60 * 1000);
                }
            } catch (Exception e) {
                logger.error("Socket error: {}", e.getMessage());
            } finally {
                if (socket != null) {
                    socket.close();
                }
            }
        }).start();
    }

    private void dealMsg(DatagramPacket packet) {
        // source ip
        InetAddress sourceAddress = packet.getAddress();
        String sourceIp = sourceAddress.getHostAddress();
        int sourcePort = packet.getPort();
        String elementId = "";
        String elementName = "";
        System.out.println("Received packet from: " + sourceIp + ":" + sourcePort);
        // 判断接收内容长度（主动上报）
        int limitedLength = 28;
        if (packet.getLength() > limitedLength) {
            // 获取网元信息
            NetElement entity = new NetElement();
            entity.setIp(sourceIp);
            List<NetElement> elements = elementService.selectNetElementList(entity);
            elementId = elements.get(0).getId();
            elementName = elements.get(0).getElementName();
            /*
             TODO: 2024/11/7  这里可以添加处理逻辑，例如将设备信息存储到数据库或发送响应等
             解析
             截取
            */
            int length = packet.getLength() - limitedLength;
            byte[] subArray = new byte[length];
            System.arraycopy(packet, limitedLength, subArray, 0, length);
            // 是否告警开头
            byte a = subArray[0];
            // JC04
            if (subArray[0] == 74 && subArray[1] == 67 && subArray[2] == 4) {

            }
            // MS05、MS07
            else if (subArray[0] == 77 && subArray[1] == 83 && (subArray[2] == 5 || subArray[2] == 7)) {
                /*协议头，NE地址1，NE地址2，NE特征字1，NE特征字2，盘类型1，盘类型2，盘类型3，盘类型4，盘地址1，盘地址2，盘特征字1，盘特征字2，备用1，备用2，盘数据长度1，盘数据长度2，盘数据长度3，盘数据长度4，
                线路1，线路1，线路1数据长度1，线路1数据长度2，线路1数据长度3，线路1数据长度4，
                告警代码1，告警状态1，(告警发生时间)年，年，月，日，时，分，秒，……，告警代码m，告警状态m，(告警发生时间)年，年，月，日，时，分，秒，*/
                // 网元地址-网块号
                int byPartNo = subArray[22];
                // 网元地址-网元号
                int byNeNo = subArray[23];
                // 网元特征字1
                int neKeyBytes1 = subArray[24];
                // 网元特征字2
                int neKeyBytes2 = subArray[25];
                // 盘总数【2字节】
                int byBoardCount = subArray[26] * 10 + subArray[27];
                // 盘类型【4字节】 28,29,30,31
                // 盘地址1
                int byGroupNo = subArray[32];
                // 盘地址2
                int byBoardAddress = subArray[33];
                // 盘特征1
                int boardKeyBytes1 = subArray[34];
                // 盘特征2
                int boardKeyBytes2 = subArray[35];
                // 备用1，备用2 36,37
                // 盘数据长度【4字节】 38,39,40,41
                int dwAlarmDataLength = subArray[38] * 1000 + subArray[39] * 100 + subArray[40] * 10 + subArray[41];

                if (dwAlarmDataLength > 0) {
                    // 线路号【2字节】42,43
                    int lineNo = subArray[42] * 10 + subArray[43];
                    // 线路数据长度[4字节] 44,45,46,47
                    int lineData = subArray[44] * 1000 + subArray[45] * 100 + subArray[46] * 10 + subArray[47];
                    List<ElementAlarm> alarms = new ArrayList<>();
                    for (int i = 0; i < lineData / 9; i++) {
                        int tmp = 47 + i * 9;
                        // 告警类型/代码
                        int alarmCode = subArray[tmp + 1]; // 0x43
                        // 告警状态1
                        int alarmStatus = subArray[tmp + 2]; // 0x13
                        // (状态变化时间)年
                        int year = subArray[tmp + 3];
                        // 年、月、日、时、分、秒
                        int year1 = subArray[tmp + 4];
                        int month = subArray[tmp + 5];
                        int day = subArray[tmp + 6];
                        int hour = subArray[tmp + 7];
                        int minute = subArray[tmp + 8];
                        int second = subArray[tmp + 9];
                        // todo 组装告警信息入库
                        ElementAlarm alarm = new ElementAlarm();
                        alarm.setId(IdUtils.simpleUUID());
                        alarm.setElementId(elementId);
                        alarm.setName(elementName);
                        alarm.setAlarmCode(alarmCode + ""); // 告警代码
                        alarm.setLineNo(lineNo + ""); // 线路号
                        alarm.setIp(sourceIp);
                        alarm.setProjectStatus(alarmStatus + ""); // 告警状态
                        alarm.setCreateBy("admin");
                        Date alarmDate = DateUtils.parseDate(String.format("%02d", year)
                                + String.format("%02d", year1) + "-"
                                + String.format("%02d", month) + "-"
                                + String.format("%02d", day) + " "
                                + String.format("%02d", hour) + ":"
                                + String.format("%02d", minute) + ":"
                                + String.format("%02d", second));
                        alarm.setCreateTime(alarmDate);
                        alarms.add(alarm);
                    }
                    if (!alarms.isEmpty()) {
                        alarmService.insertElementAlarms(alarms);
                    }
                }

            }
            // 是否性能 PS05
            else if (subArray[0] == 80 && subArray[1] == 83 && subArray[2] == 5) {
                /*协议头，性能数据类型,NE地址1，NE地址2，NE状态，备用，盘总数(高)，盘总数(低)，--28
                盘1类型1，盘1类型2，盘1类型3，盘1类型4，盘1地址1，盘1地址2，盘1状态，备用，盘1数据长度1，盘1数据长度2，盘1数据长度3，盘1数据长度4，--40
                性能数据块1长度1，性能数据块1长度2，性能数据块1长度3，性能数据块1长度4，
                线路号1，线路号1，线路1数据长度1，线路1数据长度2，线路1数据长度3，线路1数据长度4，
                性能代码1，性能(高)，性能(低)，……，性能代码n，性能(高)，性能(低)，，
                (起始时间)年，年，月，日，时，分，秒，
                (结束时间)年，年，月，日，时，分，秒*/
                // 性能数据类型
                int byDataType = subArray[22];
                // 网元地址-网块号
                int byPartNo = subArray[23];
                // 网元地址-网元号
                int byNeNo = subArray[24];
                // NE状态
                int byNeStatus = subArray[25];
                // 备用 int byBak = subArray[26];
                // 盘总数【2字节】
                int byBoardCount = subArray[27] * 10 + subArray[28];
                // 盘类型【4字节】 29,30,31,32
                // 盘地址1
                int byGroupNo = subArray[33];
                // 盘地址2
                int byBoardAddress = subArray[34];
                // 盘状态
                int byBoardStatus = subArray[35];
                // 备用 int byBak1 = subArray[36];
                // 盘数据长度【4字节】 37,38,39,40
                int dwBoardDataLen = subArray[37] * 1000 + subArray[38] * 100 + subArray[39] * 10 + subArray[40];
                // 性能块长度【4字节】41,42,43,44
                int dwPerformanceDataLength = subArray[41] * 1000 + subArray[42] * 100 + subArray[43] * 10 + subArray[44];
                if (dwPerformanceDataLength > 0) {
                    // 线路号【2字节】45,46
                    int lineNo = subArray[45] * 10 + subArray[46];
                    // 线路数据长度[4字节] 47,48,49,50
                    int lineData = subArray[47] * 1000 + subArray[48] * 100 + subArray[49] * 10 + subArray[50];
                    List<Performance> performances = new ArrayList<>();
                    for (int i = 0; i < lineData / 3; i++) {
                        int tmp = 50 + i * 3;
//                        性能代码1，性能(高)，性能(低)
                        int performanceCode = subArray[tmp + 1];
                        int performanceData = subArray[tmp + 2] * 10 + subArray[tmp + 3];
                        // todo 组装性能信息入库
                        Performance performance = new Performance();
                        performance.setId(IdUtils.simpleUUID());
                        performance.setElementId(elementId);
                        performance.setLineNo(lineNo + "");
                        performance.setCode(performanceCode + "");
                        performance.setCurrentValue(performanceData + "");
                        performance.setMaxValue("0");
                        performance.setMinValue("0");
                        performance.setMiddleValue("0");
                        performance.setStartTime("");
                        performance.setEndTime("");

                        performances.add(performance);
                    }
                    if (!performances.isEmpty()) {
                        performanceService.insertPerformances(performances);
                    }
                }
            }

        }
    }
}